package org.chaiyi.template.core.register.contractor.proxy;


import cn.hutool.core.bean.BeanUtil;
import org.chaiyi.template.core.common.contract.ContractorMethodName;
import org.chaiyi.template.core.common.exception.BaseErrorCode;
import org.chaiyi.template.core.common.repository.MongoEntity;
import org.chaiyi.template.core.common.repository.QueryInfo;
import org.chaiyi.template.core.common.supporter.MongoSupporter;
import org.chaiyi.template.core.common.util.asserts.Asserts;
import org.chaiyi.template.core.framework.mongo.Repository;
import org.springframework.beans.BeanUtils;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * Contractor动态代理工厂
 */
public class ContractorProxyFactory<T extends MongoSupporter, D extends MongoEntity> implements MethodInterceptor {

    private final Repository<T, D> repository;
    private final Class<T> supporterClass;
    private final Class<D> entityClass;


    public ContractorProxyFactory(Repository repository, Class<T> supporterClass, Class<D> entityClass) {
        this.repository = repository;
        this.supporterClass = supporterClass;
        this.entityClass = entityClass;
    }

    /**
     * 获得动态代理对象
     */
    public Object getProxy(Object bean) {
        Enhancer enhancer = new Enhancer();
        Class<?> aClass = bean.getClass();
        Constructor<?> constructor = getConstructor(aClass);
        enhancer.setSuperclass(aClass);
        enhancer.setCallback(this);

        Field[] declaredFields = bean.getClass().getDeclaredFields();
        Class<?>[] parameterTypes = constructor.getParameterTypes();
        Object[] array = new Object[parameterTypes.length];
        int index = 0;

        try {
            for (Field field : declaredFields) {
                Class<?> parameterType = parameterTypes[index];
                if (field.getType().equals(parameterType)) {
                    field.setAccessible(true);
                    array[index] = field.get(bean);
                    index++;
                }
            }
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }

        return enhancer.create(parameterTypes, array);
    }

    /**
     * 代理方法
     * 代理逻辑在此处
     */
    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        //只代理Contractor方法
        String key = ContractorMethodManager.isContractorMethod(entityClass, method, args);
        if (Asserts.isNotBlank(key)) return ContractorMethodManager.intercept(key, repository, args);

        //其他方法
        return proxy.invokeSuper(obj, args);
    }


    /**
     * 获取构造方法
     */
    private Constructor<?> getConstructor(Class<?> aClass) {
        Constructor<?>[] declaredConstructors = aClass.getDeclaredConstructors();
        BaseErrorCode.CONTRACT_EXCEPTION.throwIf(declaredConstructors.length > 1);
        return declaredConstructors[0];
    }
}
